class Pool
  attr_accessor :id, :mmes, :sgws, :mme_users_overload, :sgw_users_overload, :sgw_traffic_overload
  attr_accessor :total_pool_mme_users, :total_pool_sgw_users, :total_pool_sgw_traffic

  #create new pool
  def initialize(id)
    @id = id
    @mmes, @sgws = Array.new(), Array.new()
    @total_pool_mme_users = 0
  end

  def distribute_mme_users(area_users)
    sum = @mmes.inject(0) { |result,elem| result+elem.weight }
    @total_pool_mme_users = 0

    #allocate users for each MME
    @mmes.each do |mme|
      current_mme_users = (area_users*mme.weight/sum.to_f).ceil
      mme.users += current_mme_users
      @total_pool_mme_users += current_mme_users
    end

    #we have allocated more users than required, subtracting
    j = 0
    while (@total_pool_mme_users-area_users>0)
      j = (j+1) % @mmes.size
      @mmes[j].users-=1
      @total_pool_mme_users-=1
    end

    @mme_users_overload = [@total_pool_mme_users-@mmes.size*MME::MME_user_capacity,0].max
    puts "Total MME users allocated by pool #{@id}: #{@total_pool_mme_users}\n"
  end

  def distribute_sgw_users(area_users)
    @total_pool_sgw_users = 0

    @sgws.each do |sgw|
      current_sgw_users=(area_users/@sgws.size.to_f).ceil
      sgw.users += current_sgw_users
      @total_pool_sgw_users += current_sgw_users
    end

    #we have allocated some more users than required, subtracting
    j = 0
    while (@total_pool_sgw_users-area_users>0)
      j = (j+1) % @sgws.size
      @sgws[j].users-=1
      @total_pool_sgw_users-=1
    end

    @sgw_users_overload = [@total_pool_sgw_users-@sgws.size*SGW::SGW_user_capacity,0].max
    @sgw_traffic_overload = [$cbr*@total_pool_sgw_users-@sgws.size*SGW::SGW_traffic_capacity,0].max
    @sgws.each {|sgw| sgw.traffic = $cbr*sgw.users}

  end

  def set_overload
    @mme_users_overload = @mmes.inject(0) {|result,elem| result + elem.overload_by_users}
    @sgw_users_overload = @sgws.inject(0) {|result,elem| result + elem.overload_by_users}
    @sgw_traffic_overload = @sgws.inject(0) {|result,elem| result + elem.overload_by_traffic}
  end

  #add an MME to a pool
  def add_mme(mme)
    @mmes.push(mme)
    @mmes[-1].pools.push(@id)
  end

  #remove an MME from a pool
  def del_mme(mme)
    #puts "Trying to delete MME #{mme.id} from pool #{self.id}\n"
    self.mmes[self.mmes.find_index{|elem|elem.id==mme.id}].pools.delete(self.id)
    self.mmes.delete(mme)
  end

  def add_sgw(sgw)
    @sgws.push(sgw)
    @sgws[-1].pools.push(@id)
  end

  def del_sgw(sgw)
    #puts "Trying to delete SGW #{sgw.id} from pool #{self.id}\n"
    self.sgws[self.sgws.find_index(sgw)].pools.delete(self.id)
    self.sgws.delete(sgw)
  end

  #list all MMEs in a pool
  def list_mmes
    list = Array.new()
    @mmes.each { |mme| list.push(mme.id) }
    return list
  end

  #list all SGWs in a pool
  def list_sgws
    list = Array.new()
    @sgws.each { |sgw| list.push(sgw.id) }
    return list
  end

  def overloaded_by_mme_users?
    self.mmes.inject(0) { |result,elem| result + elem.overload_by_users } >= 0
  end

  def mmes_user_load_percentage
    @mmes.inject(0) { |result,elem| result+elem.users }/((@mmes.size*MME::MME_user_capacity).to_f)
  end

  def overloaded_by_sgw_users?
    self.sgws.inject(0) { |result,elem| result + elem.overload_by_users } >= 0
  end

  def overloaded_by_sgw_traffic?
    self.sgws.inject(0) { |result,elem| result + elem.overload_by_traffic } >= 0
  end

  def sgws_traffic_load_percentage
    @sgws.inject(0) { |result,elem| result+elem.traffic }/((@sgws.size*SGW::SGW_traffic_capacity).to_f)
  end

  def mme_exclude_possible?(mme)
    delta = (mme.users/mme.pools.size.to_f).ceil
    free = @mmes.inject(0) { |result,elem| result+(elem.id!=mme.id ? [MME::MME_user_capacity-elem.users,0].max : 0) } >= delta
    return free
  end

  def mme_exclude(mme)
    #this is the total amount of users we want to redistribute
    start_user_number = mme.users
    start_delta = (mme.users/mme.pools.size.to_f).floor
    delta = start_delta
    current_pool = $pools.find_index(self)

    @mmes.each do |target_mme|
      unless mme.id==target_mme.id
        ddelta = [delta,[MME::MME_user_capacity-target_mme.users,0].max].min
        if ddelta > 0
          mme.handover(current_pool,current_pool,$pools[current_pool].mmes.find_index(target_mme))
          delta-=ddelta
        end
        if mme.users<=(start_user_number-start_delta)
           break
        end
      end
    end
    self.del_mme(mme)
    puts "\nMME #{mme.id} excluded from pool #{self.id}\n"
  end
  
  def sgw_exclude_possible?(sgw)
    delta_users = (sgw.users/sgw.pools.size.to_f).floor
    delta_traffic = (sgw.traffic/sgw.pools.size.to_f)
    users_ok = (@sgws.inject(0) { |result,elem| result+(elem.id!=sgw.id ? SGW::SGW_user_capacity-elem.users : 0) } >= delta_users)
    traffic_ok = (@sgws.inject(0) { |result,elem| result+(elem.id!=sgw.id ? SGW::SGW_traffic_capacity-$cbr*elem.users : 0) } >= delta_traffic)
    return (users_ok && traffic_ok)
  end

  def sgw_exclude(sgw)
    start_user_number = sgw.users
    start_delta = (sgw.users/sgw.pools.size.to_f).floor
    delta = start_delta
    current_pool = $pools.find_index(self)

    @sgws.each do |target_sgw|
      unless sgw.id==target_sgw.id
        ddelta = [delta,[SGW::SGW_user_capacity-target_sgw.users,0].max].min
        if ddelta > 0
          sgw.handover(current_pool,current_pool,$pools[current_pool].sgws.find_index(target_sgw))
          delta-=ddelta
        end
        if sgw.users<=(start_user_number-start_delta)
          break
        end
      end
    end
    self.del_sgw(sgw)
    puts "\nSGW #{sgw.id} excluded from pool #{self.id}\n"
  end

end